Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

On mobile devices that support HTML5 - IOS specifically, an <audio> tag element must exist to actually play a song loaded from a server to prevent "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture." #149

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

mhdSid
Copy link

@mhdSid mhdSid commented Jan 26, 2017

Mobile browsers have always had a problem when it comes to playing audio files in the browser.

Both Chrome & Safari state that a user interaction event - click event - must occur for an audio file to be in the playing state.

Any HTTP request should occur in the same 'stack frame' of the click event.

When using Chrome on Android, we tried to request a URL from the server, to give it to SoundManager that creates an tag dynamically and feed its source with the given URL. The song didn't play.

We found a solution to this problem that is to play a blank mp3 file locally, get the song URL from the server, then replace the currently playing song with the new URL.

Plus, the tag must not be created dynamically.

…yed instantly when loading it from the server without any error - on mobile devices

Without clicking twice on the element
@mhdSid mhdSid changed the title Add the ability to append <audio> tag in the DOM on mobile devices, so a song that is loaded from the server (within a user click event method), can be played automatically without clicking twice on the element so it can be normally played Add the ability to append <audio> tag in the DOM on mobile devices, so a song that is loaded from the server (within a user click event method), can be played automatically without clicking twice on the element Jan 26, 2017
@mhdSid mhdSid changed the title Add the ability to append <audio> tag in the DOM on mobile devices, so a song that is loaded from the server (within a user click event method), can be played automatically without clicking twice on the element On mobile devices that support HTML5, an <audio> tag element must exist to play a song loaded from a server to prevent "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture." Jan 27, 2017
@DvirSh
Copy link

DvirSh commented Jan 30, 2017

Hi, Iv'e tried using the code you wrote here inside my react application (AKA creating the audio element as soon as the application loads and before I play the first sound).
It didn't work for me - the error message no longer appears but I still cannot hear the sounds until I'm interacting with the view.
Anything I might be missing?

@mhdSid mhdSid changed the title On mobile devices that support HTML5, an <audio> tag element must exist to play a song loaded from a server to prevent "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture." On mobile devices that support HTML5 - IOS specifically, an <audio> tag element must exist to play a song loaded from a server to prevent "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture." Jan 30, 2017
@mhdSid mhdSid changed the title On mobile devices that support HTML5 - IOS specifically, an <audio> tag element must exist to play a song loaded from a server to prevent "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture." On mobile devices that support HTML5, an <audio> tag element must exist to actually play a song loaded from a server to prevent "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture." Jan 30, 2017
@mhdSid mhdSid changed the title On mobile devices that support HTML5, an <audio> tag element must exist to actually play a song loaded from a server to prevent "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture." On mobile devices that support HTML5 - IOS specifically, an <audio> tag element must exist to actually play a song loaded from a server to prevent "Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture." Jan 30, 2017
@mhdSid
Copy link
Author

mhdSid commented Jan 30, 2017

On top of updating SM2 to help prevent this issue, we played a blank.mp3 file and once we want to play the actual desired song, we pause, switch the blank.mp3 sound's URL with the new desired URL, and play again.

@mhdSid
Copy link
Author

mhdSid commented Jan 30, 2017

Hope this help your issue. Cheers!

@DvirSh
Copy link

DvirSh commented Mar 9, 2017

Unfortunately it does not work for me. I'm trying to use the native Audio javascript component, such as:

sound = new Audio(emptySoundUrl);
sound.play();
setTimeout(() => {
    sound.pause();
    sound.src = realUrl;
    sound.play();
}, 3000);

But it still prompts the error message that the user must initiate the operation with a gesture...
Any suggestion?

(BTW it seems there's nobody to accept the PR :) )

@mhdSid
Copy link
Author

mhdSid commented Mar 10, 2017

You shouldn't use it as such, but you should initialise soundManager and it creates an HTMLAudioElement manually and place it in the DOM.

@scottschiller
Copy link
Owner

Sorry for the late follow-up on this, I'm curious about this PR but hesitant to simply merge it - something doesn't sound quite right about the user experience.

It sounds like you are saying the user needs to tap / click / act twice to get audio to start, which is undesirable. However, SM2 only requires one click/tap to start audio.

You can create and play a sound from a single user action in SM2, but it must be synchronous - no setTimeout(), etc., allowed between the user action and the SM2 createSound() / play() calls.

It seems you're suggesting that if an <audio> element exists in the DOM, then audio playback can start with a single tap/click, or possibly no user interaction.

My experience is that on mobile, user action is always required for playback to start - and on iOS, there is no difference whether the Audio() element is in JS, or attached as a live element in the DOM - so this PR will not change that.

@mhdSid
Copy link
Author

mhdSid commented May 21, 2017 via email

@mhdSid
Copy link
Author

mhdSid commented May 21, 2017 via email

@mhdSid
Copy link
Author

mhdSid commented Mar 14, 2018

@Lazey5 Check this out:
It adapts to any device. Takes care of all the matters that you & I have faced.
After dwelling in all web audio matters, I've spent two months writing this.
https://www.npmjs.com/package/anghami-audio-manager

@mhdSid
Copy link
Author

mhdSid commented Mar 14, 2018

@scottschiller
Dear Scott,

At Anghami, we heavily use SoundManager2 in order to give a pleasant music experience on the web. However, on some browsers such as Instagram browser, iOS, android, PS4, we have faced a lot of issues with SoundManager2 in order to fetch songs from the server and play.
As a perfect solution for this, we have decided to drop SoundManager2 on these browsers except for web, and create our own AudioManager

Please I would like you to check it out and give me a feedback.

@scottschiller
Copy link
Owner

scottschiller commented Mar 15, 2018

Thanks for the update, sorry for the random spam comments above - reported.

I still haven't worked this PR in, as you should be able to initiate a play() request directly from a user action like a click or touch with SM2 as-is. I realize this doesn't cover your particular case, I will need to address that.

If you're trying to work around asynchonous fetches to get the MP3 (for example) you want to play and that's why you must play a blank .mp3 first, my $.02 is that you're playing with fire in hoping that - for example, playing a silent sound and then having it onfinish() and go to the next URL when it's known - will work, but sounds pretty risky.

Notwithstanding, you've indicated you found a solution and SM2 should also handle this - your point about the Audio() / <audio> (?) being created on the fly, i.e., at the time of click, might be the distinction for the issue you're describing. That's interesting.

SM2 has existed for over 10 years now - not to say that means it's good by default, but it has gone through a lot of testing and has dealt with obscure browser bugs along the way.

Mobile is picking up the pace, and desktop is starting to adapt mobile's auto-play blocking as well. I have intent to move SM2 to 100% HTML5 soon, though it won't matter much with regards to retiring of Flash or Chrome's stated deadline for the new auto-play restrictions. Ideally, developers aren't running afoul of those rules unless there's a very specific exception like in your async case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants